/*
 * CcCalcute.c
 *
 *  Created on: 2012/04/24
 *      Author: guanxiaoying
 */
#include "../coredef.h"
#include "cc.h"

static VARVALUE ccCalAdditiveInteger( VARVALUE varLeft , VARVALUE varRight  );
static VARVALUE ccCalSubtractionInteger( VARVALUE varLeft, VARVALUE varRight );
static S4 gblCalcuteFlg = 0;
/*
 * CcCalInitial
 * 		initial
 */
VOID CcCalInitial(VOID){
	;
	//nothing to do
}
/*
 * ccCalGetRealBitStateOfNegative
 * 		get real bit state in memory
 * 		@stValue  the integer
 *		@size     the bytes of type
 *		@bFillWithZero  fill the superior bits with 0 which 's out of range of type
 *		                when it's true
 */
static VOID ccCalGetRealBitStateOfNegative( VARVALUE * stValue, U4 size, BOOL bFillWithZero ){
	if( stValue->sign < 0 ){
		/* convert absolute value to the real bit state when the value is negative */
		stValue->u8Remainder = ~stValue->u8Remainder;
		stValue->u8Remainder++;
		if( bFillWithZero ){
			stValue->u8Remainder &= U8_MAXVALUE >> ((8 - size)*CHARBIT);
		}
	}
	/* the absolute value is same with the real bit state when the value is positive */
}
/*
 * ccCalGetAbsoluteValue
 * 		get absolute value  |value| when the value is in the state
 * 		that's same with real bit state in memory
 * 		@stValue  the integer
 *		@size     the bytes of type
 */
static VOID ccCalGetAbsoluteValue( VARVALUE * stValue, U4 size ){
	if( stValue->sign < 0 ){
		/* convert  real bit state to absolute value when the value is negative */
		stValue->u8Remainder = ~stValue->u8Remainder;
		stValue->u8Remainder++;
	}
	stValue->u8Remainder &= U8_MAXVALUE >> ((8 - size)*CHARBIT);
}
/*
 * ccCalIsNegative
 * 		negative if the  most superior bit was 1.
 * 		@stValue  the integer
 *		@size     the bytes of type
 */
static BOOL ccCalIsNegative( VARVALUE * stValue, U4 size ){
	if( stValue->u8Remainder & ( 1ULL << ((size*CHARBIT)-1))){
		return TRUE;
	}
	return FALSE;
}
/*
 * ccCalLeftShift
 * 		shift left
 * 		@astLV  the left operand
 *		@pstRight  the right operand
 */
static AST ccCalLeftShift( AST astLV, VARVALUE * pstRight ){
	AST astLType = stValueInfoAccess.type.get( astLV );
	U4 size = stTypeInfoAccess.size.get( astLType );
	VARVALUE stLeft, stRes;
	U2 leftBit;
	if( pstRight->u8Remainder >= size * CHARBIT ){
		/* the right operand is too large */
		gblCalcuteFlg |= CAL_SHIFT_OVERFLOW;
		if( stCoreEnvInfo.ucShiftWhenOverflow == OPT_SHIFT_BITNUM_REMAINDER ){
			pstRight->u8Remainder %= size * CHARBIT;
		}else{
			return CcValueGetZero( astLType );
		}
	}
	stLeft = CcValueGetInteger(astLV);
	stRes.sign = stLeft.sign;
	if( stCoreEnvInfo.ucShiftKind != OPT_SHIFT_ARITH ){
		ccCalGetRealBitStateOfNegative( &stLeft, size, FALSE );
	}

	/* get the most superior bit which is 1, and save to 'leftBit */
	leftBit = CHARBIT*sizeof( stLeft.u8Remainder );
	while( leftBit > 1  ){
		if( stLeft.u8Remainder & (1ULL<<(leftBit-1)) ){
			break;
		}
		leftBit--;
	}
	/* overflow? */
	if( stRes.sign > 0 ){
		if( leftBit + pstRight->u8Remainder > size*CHARBIT ){
			gblCalcuteFlg = CAL_OVERFLOW;
		}
	}else{
		if( leftBit + pstRight->u8Remainder > size*CHARBIT - 1 ){
			gblCalcuteFlg = CAL_OVERFLOW;
		}
	}
	stRes.u8Remainder = stLeft.u8Remainder << pstRight->u8Remainder;
	if( stCoreEnvInfo.ucShiftKind != OPT_SHIFT_ARITH ){
		if( ccCalIsNegative( &stRes, size ) ){
			stRes.sign = -1;
		}
		ccCalGetAbsoluteValue(&stRes, size );
	}

	return CcValueAddVarValue( astLType, stRes );
}
/*
 * ccCalRightShift
 * 		shift right
 * 		@astLV  the left operand
 *		@pstRight  the right operand
 */
static AST ccCalRightShift( AST astLV, VARVALUE * pstRight ){
	AST astLType = stValueInfoAccess.type.get( astLV );
	U4 size = stTypeInfoAccess.size.get( astLType );
	VARVALUE stLeft, stRes;
	if( pstRight->u8Remainder >= size * CHARBIT ){
		/* the right operand is too large */
		gblCalcuteFlg |= CAL_SHIFT_OVERFLOW;
		if( stCoreEnvInfo.ucShiftWhenOverflow == OPT_SHIFT_BITNUM_REMAINDER ){
			pstRight->u8Remainder %= size * CHARBIT;
		}else if( pstRight->sign > 0 ){
			return CcValueGetZero( astLType );
		}else{
			pstRight->sign = -1;
			pstRight->u4Quotient = 0;
			pstRight->u8Remainder = 1;
			return CcValueAddVarValue( astLType, stLeft );
		}
	}
	stLeft = CcValueGetInteger(astLV);
	stRes.sign = stLeft.sign;
	if( stCoreEnvInfo.ucShiftKind != OPT_SHIFT_ARITH ){
		ccCalGetRealBitStateOfNegative( &stLeft, size, TRUE );
	}
	stRes.u8Remainder = stLeft.u8Remainder >> pstRight->u8Remainder;
	if( stCoreEnvInfo.ucShiftKind == OPT_SHIFT_ARITH ){
		if( stRes.sign < 0 ){
			if( stRes.u8Remainder == 0 ){
				/* the final value of negative is -1  */
				stRes.u8Remainder = 1;
			}
		}
	}else{
		if( ccCalIsNegative( &stRes, size ) ){
			stRes.sign = -1;
		}
		ccCalGetAbsoluteValue(&stRes, size );
	}
	return CcValueAddVarValue( astLType, stRes );
}
/*
 * ccCalMultiplicativeInteger
 * 		multiplicative for integers
 * 		@varLeft  the left operand
 *		@varRight  the right operand
 */
static VARVALUE  ccCalMultiplicativeInteger ( VARVALUE varLeft, VARVALUE varRight ){
	VARVALUE stres;
//	U4 bit;
	U4 leftBit =0;
	U4 rightBit = 0;
	stres.u4Quotient = 0;
	if (varLeft.u8Remainder == 0 || varRight.u8Remainder == 0 ){
		stres.sign = 1;
		stres.u8Remainder = 0;
		return stres;
	}
	/* get the sign of result  */
	if( varLeft.sign == varRight.sign ){
		stres.sign = 1;
	}else{
		stres.sign = -1;
	}
	/* left operand: get the most superior bit which is 1, and save to 'leftBit */
	leftBit = CHARBIT*sizeof( varLeft.u8Remainder );
	while( leftBit > 1  ){
		if( varLeft.u8Remainder & (1ULL<<(leftBit-1)) ){
			break;
		}
		leftBit--;
	}
	/* right operand:  get the most superior bit which is 1, and save to 'rightBit */
	rightBit = CHARBIT*sizeof( varRight.u8Remainder );
	while( rightBit > 1  ){
		if( varRight.u8Remainder & (1ULL<<(rightBit-1)) ){
			break;
		}
		rightBit--;
	}
//	bit = CHARBIT*sizeof(stres.u8Remainder);
	if( leftBit + rightBit - 1 > CHARBIT*(sizeof(stres.u8Remainder))  ){
		/* overflow */
		stres.overflow = CAL_OVERFLOW;
		rightBit = CHARBIT*(sizeof(stres.u8Remainder)+sizeof(stres.u4Quotient))  + 1 - leftBit;
	}
	stres.u8Remainder = varLeft.u8Remainder * varRight.u8Remainder;
	stres.u4Quotient = 0;
	return stres;

}
/*
 * ccCalDivisionInteger
 * 		Division for integers
 * 		@varLeft  the left operand
 *		@varRight  the right operand
 */
static VARVALUE  ccCalDivisionInteger ( VARVALUE varLeft, VARVALUE varRight ){
	VARVALUE stres;
	stres.u4Quotient = 0;
	if (varLeft.u8Remainder == 0 ){
		stres.sign = 1;
		stres.u8Remainder = 0;
		return stres;
	}
	if( varLeft.sign == varRight.sign ){
		stres.sign = 1;
	}else{
		stres.sign = -1;
	}
	if( varRight.u8Remainder == 0 ){
		stres.overflow = CAL_DIVIDE_ZERO;
		return stres;
	}
	stres.u8Remainder = varLeft.u8Remainder/ varRight.u8Remainder;
	if( 0 == varLeft.u8Remainder% varRight.u8Remainder ){
		return stres;
	}
	if( varLeft.sign > 0 && varRight.sign < 0 ){
		if( stCoreEnvInfo.ucModuloSign == OPT_MODULO_SIGNED ){
			stres.u8Remainder++;
		}
	}else if( varLeft.sign < 0 && varRight.sign < 0 ){
		if (stCoreEnvInfo.ucModuloSign == OPT_MODULO_UNSIGNED ){
			stres.u8Remainder++;
		}
	}else if( varLeft.sign < 0 && varRight.sign > 0 ){
		if (stCoreEnvInfo.ucModuloSign == OPT_MODULO_UNSIGNED ){
			stres.u8Remainder++;
		}
	}
	return stres;

}
/*
 * ccCalRemainder
 * 		modulo for integers
 * 		@varLeft  the left operand
 *		@varRight  the right operand
 */
static VARVALUE  ccCalRemainder( VARVALUE varLeft, VARVALUE varRight ){
	VARVALUE stres;
	stres.u4Quotient = 0;
	if (varLeft.u8Remainder == 0 ){
		stres.sign = 1;
		stres.u8Remainder = 0;
		return stres;
	}
	if( varRight.u8Remainder == 0 ){
		stres.sign = 1;
		stres.overflow = CAL_DIVIDE_ZERO;
		stres.u8Remainder = 0;
		return stres;
	}
	stres.u8Remainder = varLeft.u8Remainder% varRight.u8Remainder;
	stres.sign = 1;
	if( stres.u8Remainder == 0 ){
		return stres;
	}
	if( varLeft.sign > 0 && varRight.sign < 0 ){
		if( stCoreEnvInfo.ucModuloSign == OPT_MODULO_SIGNED ){
			varLeft.sign = -1;
			stres.u8Remainder = varRight.u8Remainder - stres.u8Remainder;
		}
	}else if( varLeft.sign < 0 && varRight.sign < 0 ){
		if (stCoreEnvInfo.ucModuloSign == OPT_MODULO_UNSIGNED ){
			varLeft.sign = 1;
			stres.u8Remainder = varRight.u8Remainder - stres.u8Remainder;
		}
	}else if( varLeft.sign < 0 && varRight.sign > 0 ){
		if (stCoreEnvInfo.ucModuloSign == OPT_MODULO_UNSIGNED ){
			varLeft.sign = 1;
			stres.u8Remainder = varRight.u8Remainder - stres.u8Remainder;
		}
	}
	return stres;

}
/*
 * ccCalAdditiveInteger
 * 		Additive for integers
 * 		@varLeft  the left operand
 *		@varRight  the right operand
 */
static VARVALUE ccCalAdditiveInteger( VARVALUE varLeft , VARVALUE varRight ){
	if( varLeft.sign == varRight.sign ){
		varLeft.u8Remainder += varRight.u8Remainder;
		if( varLeft.u8Remainder < varRight.u8Remainder ){
			varLeft.overflow = CAL_OVERFLOW;
		}
	}else if( varLeft.u8Remainder >= varRight.u8Remainder ){
		varLeft.u8Remainder -= varRight.u8Remainder ;
	}else{
		varLeft.sign = varRight.sign;
		varLeft.u8Remainder = varRight.u8Remainder - varLeft.u8Remainder;
	}
	return varLeft;
}
/*
 * ccCalSubtractionInteger
 * 		Subtraction for integers
 * 		@varLeft  the left operand
 *		@varRight  the right operand
 */
static VARVALUE ccCalSubtractionInteger( VARVALUE varLeft, VARVALUE varRight ){
	varRight.sign = - varRight.sign;
	varLeft = ccCalAdditiveInteger( varLeft, varRight );
	return varLeft;
}
/*
 * ccCalAdditiveFloating
 * 		Additive for floating numbers
 * 		@flLeft  the left operand
 *		@flRight  the right operand
 */
static DOUBLE ccCalAdditiveFloating( DOUBLE flLeft, DOUBLE flRight ){
	flLeft = flLeft + flRight;
	return flLeft;
}
/*
 * ccCalAdditiveFloating
 * 		Subtraction for floating numbers
 * 		@flLeft  the left operand
 *		@flRight  the right operand
 */
static DOUBLE ccCalSubtractionFloating( DOUBLE flLeft, DOUBLE flRight ){
	flLeft = flLeft - flRight;
	return flLeft;
}
/*
 * ccCalCastInt2Int
 * 		cast a integer to another integer type
 * 		@stIn  value
 *		@astType  another integer type
 */
static VARVALUE ccCalCastInt2Int( VARVALUE stIn, AST astType ){
	U4 size = stTypeInfoAccess.size.get(astType );
	VARVALUE  stRes;
	BOOL bSign = FALSE;
	S2   bOldSign = stIn.sign;

	/* type: signed or unsigned  */
	switch( astType ){
	case TYPE_CHAR:
		if( stCoreEnvInfo.ucCharSign == OPT_CHAR_SIGNED ){
			bSign = TRUE;
		}
		break;
	case TYPE_SIGNED_CHAR:
	case TYPE_SHORT:
	case TYPE_SIGNED_SHORT:
	case TYPE_INT:
	case TYPE_SIGNED_INT:
	case TYPE_LONG:
	case TYPE_SIGNED_LONG:
	case TYPE_LONG_LONG:
	case TYPE_SIGNED_LONG_LONG:
		bSign = TRUE;
		break;
	}
	if( stIn.u8Remainder >> (size*CHARBIT)){
		gblCalcuteFlg = CAL_CAST_INT_LOSTDATA;
	}
	ccCalGetRealBitStateOfNegative( &stIn, size, FALSE );
	stRes.u8Remainder = stIn.u8Remainder;
	if( bSign &&  ccCalIsNegative( &stRes, size )){
		stRes.sign = -1;
	}else{
		stRes.sign = 1;
	}
	if( bOldSign != stRes.sign ){
		gblCalcuteFlg |= CAL_CAST_INT_CHANGEFLG;
	}
	/* ccCalGetAbsoluteValue: kill the superior bits that are out of range  */
	ccCalGetAbsoluteValue( &stRes, size );
	return stRes;
}
/*
 * ccCalCastInt2Floating
 * 		cast a integer to another floating type
 * 		@stIn  value
 *		@astType  another floating type
 */
static DOUBLE ccCalCastInt2Floating( VARVALUE stIn, AST astType ){
	if( stIn.sign > 0 ){
		return (DOUBLE)stIn.u8Remainder;
	}else{
		return (DOUBLE)(-1.)*stIn.u8Remainder;
	}
}
/*
 * ccCalCastInt2Floating
 * 		cast a floating number to another integer type
 * 		@stIn  value
 *		@astType  another integer type
 */
static VARVALUE ccCalCastFloating2Int( DOUBLE dbV, AST astType ){
	VARVALUE stRes;
	if( dbV > 0 ){
		stRes.sign = 1;
		stRes.u8Remainder = (U8)dbV;
	}else{
		stRes.sign = -1;
		stRes.u8Remainder = (U8) -dbV;
	}
	gblCalcuteFlg = CAL_CAST_FLOAT2INT;
	return stRes;
}
/*
 * CcCalMinus
 * 		calculate the Unary minus-op.
 * 		@astValue  operand
 */
AST CcCalMinus( AST astValue ){
	AST astType = stValueInfoAccess.type.get( astValue );
	VARVALUE value;
	if( CcTypeIsFloating( astType ) ){
		DOUBLE dbValue = CcValueGetFloating( astValue );
		dbValue = -dbValue;
		return CcValueAddFloating( astType, dbValue );
	}
	if( CcTypeIsSigned( astType )){
		value = CcValueGetInteger( astValue );
		value.sign = -value.sign;
		return CcValueAddVarValue( astType, value );
	}
	value = CcValueGetInteger( astValue );
	value.sign = -1;
	ccCalGetRealBitStateOfNegative( &value, stTypeInfoAccess.size.get( astType ), TRUE );
	value.sign = 1;
	gblCalcuteFlg = CAL_SIGN_OVERFLOW;
	return CcValueAddVarValue( astType, value );
}
/*
 * CcCalNegation
 * 		calculate the Unary ! op.
 * 		@astValue  operand
 */
AST CcCalNegation( AST astValue ){
	AST astType = stValueInfoAccess.type.get( astValue );
	if( CcValueIsZero( astValue )){
		return CcValueGetOne(astType) ;
	}
	return CcValueGetZero(astType) ;
}
/*
 * CcCalBitNegation
 * 		calculate the Unary ~ op.
 * 		@astValue  operand
 */
AST CcCalBitNegation( AST astValue ){
	AST astType = stValueInfoAccess.type.get( astValue );
	VARVALUE varLeft;
	U4 size;

	if( CcTypeIsFloating( astType ) ){
		return 0;
	}
	size = stTypeInfoAccess.size.get( astType );
	varLeft =CcValueGetInteger( astValue );
	ccCalGetRealBitStateOfNegative(&varLeft, size, FALSE );
	varLeft.sign = 1;
	if( CcTypeIsSigned( astType ) ){
		if( ccCalIsNegative( &varLeft, size ) ){
			varLeft.sign = -1;
		}
	}
	ccCalGetAbsoluteValue( &varLeft, size );
	return CcValueAddVarValue( astType, varLeft );
}
/*
 * CcCalMultiplicative
 * 		calculate the Multiplicative
 * 		@astLV  operand
 * 		@astRV  operand
 * 		@astType  type of result
 */
AST CcCalMultiplicative( AST astLV, AST astRV, AST astType ){
	AST astLType = stValueInfoAccess.type.get( astLV );
	AST astRType = stValueInfoAccess.type.get( astRV );

	if( CcTypeIsInteger( astType )){
		VARVALUE varLeft;
		VARVALUE varRight;
		if( astLType != astType ){
			if( CcTypeIsInteger( astLType ) ){
				varLeft = ccCalCastInt2Int(  CcValueGetInteger( astLV ), astType );
			}else{
				varLeft = ccCalCastFloating2Int( CcValueGetFloating( astLV ), astType );
			}
		}else{
			varLeft = CcValueGetInteger( astLV );
		}
		if( astRType != astType ){
			if( CcTypeIsInteger( astRType ) ){
				varRight = ccCalCastInt2Int( CcValueGetInteger( astRV ), astType );
			}else{
				varRight = ccCalCastFloating2Int( CcValueGetFloating( astRV ), astType );
			}
		}else{
			varRight = CcValueGetInteger( astRV );
		}
		varLeft = ccCalMultiplicativeInteger( varLeft, varRight );
		if( varLeft.overflow == CAL_OVERFLOW ){
			gblCalcuteFlg = CAL_OVERFLOW;
		}
		return CcValueAddVarValue( astType, varLeft );
	}else{
		DOUBLE varLeft;
		DOUBLE varRight;
		if( astLType != astType ){
			if( CcTypeIsInteger( astLType ) ){
				varLeft = ccCalCastInt2Floating(  CcValueGetInteger( astLV ), astType );
			}else{
				varLeft = CcValueGetFloating( astLV );
			}
		}else{
			varLeft = CcValueGetFloating( astLV );
		}
		if( astRType != astType ){
			if( CcTypeIsInteger( astRType ) ){
				varRight = ccCalCastInt2Floating( CcValueGetInteger( astRV ), astType );
			}else{
				varRight = CcValueGetFloating( astRV );
			}
		}else{
			varRight = CcValueGetFloating( astRV );
		}
		/*debug,12/11/14,S*/
		/*varLeft = ccCalAdditiveFloating( varLeft, varRight );*/
		varLeft = varLeft * varRight;
		/*debug,12/11/14,E*/
		return CcValueAddFloating( astType, varLeft );
	}
}
/*
 * CcCalDivision
 * 		calculate division
 * 		@astLV  operand
 * 		@astRV  operand
 * 		@astType  type of result
 */

AST CcCalDivision( AST astLV, AST astRV , AST astType ){
	AST astLType = stValueInfoAccess.type.get( astLV );
	AST astRType = stValueInfoAccess.type.get( astRV );

	if( CcTypeIsInteger( astType )){
		VARVALUE varLeft;
		VARVALUE varRight;
		if( astLType != astType ){
			if( CcTypeIsInteger( astLType ) ){
				varLeft = ccCalCastInt2Int(  CcValueGetInteger( astLV ), astType );
			}else{
				varLeft = ccCalCastFloating2Int( CcValueGetFloating( astLV ), astType );
			}
		}else{
			varLeft = CcValueGetInteger( astLV );
		}
		if( astRType != astType ){
			if( CcTypeIsInteger( astRType ) ){
				varRight = ccCalCastInt2Int( CcValueGetInteger( astRV ), astType );
			}else{
				varRight = ccCalCastFloating2Int( CcValueGetFloating( astRV ), astType );
			}
		}else{
			varRight = CcValueGetInteger( astRV );
		}
		varLeft = ccCalDivisionInteger( varLeft, varRight );
		if( varLeft.overflow == CAL_DIVIDE_ZERO ){
			gblCalcuteFlg = CAL_DIVIDE_ZERO;
			return 0;
		}
		return CcValueAddVarValue( astType, varLeft );
	}else{
		DOUBLE varLeft;
		DOUBLE varRight;
		if( astLType != astType ){
			if( CcTypeIsInteger( astLType ) ){
				varLeft = ccCalCastInt2Floating(  CcValueGetInteger( astLV ), astType );
			}else{
				varLeft = CcValueGetFloating( astLV );
			}
		}else{
			varLeft = CcValueGetFloating( astLV );
		}
		if( astRType != astType ){
			if( CcTypeIsInteger( astRType ) ){
				varRight = ccCalCastInt2Floating( CcValueGetInteger( astRV ), astType );
			}else{
				varRight = CcValueGetFloating( astRV );
			}
		}else{
			varRight = CcValueGetFloating( astRV );
		}
		if(varRight == 0.){
			gblCalcuteFlg = CAL_DIVIDE_ZERO;
			return 0;
		}
		varLeft = varLeft/varRight;
		return CcValueAddFloating( astType, varLeft );
	}
}
/*
 * CcCalRemainder
 * 		calculate %
 * 		@astLV  operand
 * 		@astRV  operand
 * 		@astType  type of result
 */
AST CcCalRemainder( AST astLV, AST astRV, AST astType ){
	AST astLType = stValueInfoAccess.type.get( astLV );
	AST astRType = stValueInfoAccess.type.get( astRV );

	if( CcTypeIsInteger( astType )){
		VARVALUE varLeft;
		VARVALUE varRight;
		if( astLType != astType ){
			if( CcTypeIsInteger( astLType ) ){
				varLeft = ccCalCastInt2Int(  CcValueGetInteger( astLV ), astType );
			}else{
				varLeft = ccCalCastFloating2Int( CcValueGetFloating( astLV ), astType );
			}
		}else{
			varLeft = CcValueGetInteger( astLV );
		}
		if( astRType != astType ){
			if( CcTypeIsInteger( astRType ) ){
				varRight = ccCalCastInt2Int( CcValueGetInteger( astRV ), astType );
			}else{
				varRight = ccCalCastFloating2Int( CcValueGetFloating( astRV ), astType );
			}
		}else{
			varRight = CcValueGetInteger( astRV );
		}
		varLeft = ccCalRemainder( varLeft, varRight );
		if(varLeft.overflow == CAL_DIVIDE_ZERO){
			gblCalcuteFlg = CAL_DIVIDE_ZERO;
			return 0;
		}
		return CcValueAddVarValue( astType, varLeft );
	}
	return 0;
}
/*
 * CcCalLeftShift
 * 		calculate <<
 * 		@astLV  operand
 * 		@astRV  operand
 */
AST CcCalLeftShift( AST astLV, AST  astRV ){
	AST astLType = stValueInfoAccess.type.get( astLV );
	AST astRType = stValueInfoAccess.type.get( astRV );
	VARVALUE stRight;
	if( CcTypeIsInteger( astLType ) && CcTypeIsInteger ( astRType ) ){
		stRight = CcValueGetInteger(astRV);
		if( stRight.sign < 0 ){
			gblCalcuteFlg = CAL_SHIFT_NEGATIVE;
			if( stCoreEnvInfo.ucShiftWhenNegative == OPT_SHIFT_NEG_2_UNSIGNED ){
				stRight.sign = 1;
				stRight.u8Remainder = U8_MAXVALUE - stRight.u8Remainder + 1;
			}else{
				// OPT_SHIFT_NEG_CHANGE_OP
				return ccCalRightShift( astLV, &stRight );
			}
		}
		return ccCalLeftShift( astLV, &stRight );
	}
	return 0;
}
/*
 * CcCalRightShift
 * 		calculate >>
 * 		@astLV  operand
 * 		@astRV  operand
 */
AST CcCalRightShift( AST astLV, AST astRV ){
	AST astLType = stValueInfoAccess.type.get( astLV );
	AST astRType = stValueInfoAccess.type.get( astRV );
	VARVALUE stRight;
	if( CcTypeIsInteger( astLType ) && CcTypeIsInteger ( astRType ) ){
		stRight = CcValueGetInteger(astRV);
		if( stRight.sign < 0 ){
			gblCalcuteFlg = CAL_SHIFT_NEGATIVE;
			if( stCoreEnvInfo.ucShiftWhenNegative == OPT_SHIFT_NEG_2_UNSIGNED ){
				stRight.sign = 1;
				stRight.u8Remainder = U8_MAXVALUE - stRight.u8Remainder + 1;
			}else{
				// OPT_SHIFT_NEG_CHANGE_OP
				return ccCalLeftShift( astLV, &stRight );
			}
		}
		return ccCalRightShift( astLV, &stRight );
	}
	return 0;
}
/*
 * CcCalBitAnd
 * 		calculate &
 * 		@astLV  operand
 * 		@astRV  operand
 * 		@astType  type of result
 */
AST CcCalBitAnd( AST astLV, AST astRV, AST astType ){
	VARVALUE varLeft;
	VARVALUE varRight;
	VARVALUE stRes;
	U4 size = stTypeInfoAccess.size.get( astType );
	if( CcTypeIsInteger( astType )){
		varLeft = ccCalCastInt2Int(  CcValueGetInteger( astLV ), astType );
		varRight = ccCalCastInt2Int( CcValueGetInteger( astRV ), astType );
		ccCalGetRealBitStateOfNegative( &varLeft, size, FALSE );
		ccCalGetRealBitStateOfNegative( &varRight, size, FALSE  );
		stRes.u8Remainder = varLeft.u8Remainder & varRight.u8Remainder;
		if( CcTypeIsSigned( astType ) &&  ccCalIsNegative( &stRes, size )){
			stRes.sign = -1;
		}else{
			stRes.sign = 1;
		}
		ccCalGetAbsoluteValue( &stRes, size );
		return CcValueAddVarValue( astType, stRes );
	}
	return 0;
}
/*
 * CcCalBitExOr
 * 		calculate ^
 * 		@astLV  operand
 * 		@astRV  operand
 * 		@astType  type of result
 */
AST CcCalBitExOr( AST astLV,  AST astRV, AST astType ){
	VARVALUE varLeft;
	VARVALUE varRight;
	VARVALUE stRes;
	U4 size = stTypeInfoAccess.size.get( astType );
	if( CcTypeIsInteger( astType )){
		varLeft = ccCalCastInt2Int(  CcValueGetInteger( astLV ), astType );
		varRight = ccCalCastInt2Int( CcValueGetInteger( astRV ), astType );
		ccCalGetRealBitStateOfNegative( &varLeft, size, FALSE );
		ccCalGetRealBitStateOfNegative( &varRight, size, FALSE  );
		stRes.u8Remainder = varLeft.u8Remainder ^ varRight.u8Remainder;
		if( CcTypeIsSigned( astType ) &&  ccCalIsNegative( &stRes, size )){
			stRes.sign = -1;
		}else{
			stRes.sign = 1;
		}
		ccCalGetAbsoluteValue( &stRes, size );
		return CcValueAddVarValue( astType, stRes );
	}
	return 0;
}
/*
 * CcCalBitInOr
 * 		calculate |
 * 		@astLV  operand
 * 		@astRV  operand
 * 		@astType  type of result
 */
AST CcCalBitInOr( AST astLV, AST astRV, AST astType ){
	VARVALUE varLeft;
	VARVALUE varRight;
	VARVALUE stRes;
	U4 size = stTypeInfoAccess.size.get( astType );
	if( CcTypeIsInteger( astType )){
		varLeft = ccCalCastInt2Int(  CcValueGetInteger( astLV ), astType );
		varRight = ccCalCastInt2Int( CcValueGetInteger( astRV ), astType );
		ccCalGetRealBitStateOfNegative( &varLeft, size, FALSE );
		ccCalGetRealBitStateOfNegative( &varRight, size, FALSE  );
		stRes.u8Remainder = varLeft.u8Remainder | varRight.u8Remainder;
		if( CcTypeIsSigned( astType ) &&  ccCalIsNegative( &stRes, size )){
			stRes.sign = -1;
		}else{
			stRes.sign = 1;
		}
		ccCalGetAbsoluteValue( &stRes, size );
		return CcValueAddVarValue( astType, stRes );
	}
	return 0;
}
/*
 * CcCalAdditive
 * 		calculate +
 * 		@astLV  operand
 * 		@astRV  operand
 * 		@astType  type of result
 */
AST CcCalAdditive( AST astLV, AST astRV, AST astType ){
	AST astLType = stValueInfoAccess.type.get( astLV );
	AST astRType = stValueInfoAccess.type.get( astRV );

	if( CcTypeIsInteger( astType )){
		VARVALUE varLeft;
		VARVALUE varRight;
		if( astLType != astType ){
			if( CcTypeIsInteger( astLType ) ){
				varLeft = ccCalCastInt2Int(  CcValueGetInteger( astLV ), astType );
			}else{
				varLeft = ccCalCastFloating2Int( CcValueGetFloating( astLV ), astType );
			}
		}else{
			varLeft = CcValueGetInteger( astLV );
		}
		if( astRType != astType ){
			if( CcTypeIsInteger( astRType ) ){
				varRight = ccCalCastInt2Int( CcValueGetInteger( astRV ), astType );
			}else{
				varRight = ccCalCastFloating2Int( CcValueGetFloating( astRV ), astType );
			}
		}else{
			varRight = CcValueGetInteger( astRV );
		}
		varLeft = ccCalAdditiveInteger( varLeft, varRight );
		if( varLeft.overflow == CAL_OVERFLOW ){
			gblCalcuteFlg = CAL_OVERFLOW;
		}
		return CcValueAddVarValue( astType, varLeft );
	}else{
		DOUBLE varLeft;
		DOUBLE varRight;
		if( astLType != astType ){
			if( CcTypeIsInteger( astLType ) ){
				varLeft = ccCalCastInt2Floating(  CcValueGetInteger( astLV ), astType );
			}else{
				varLeft = CcValueGetFloating( astLV );
			}
		}else{
			varLeft = CcValueGetFloating( astLV );
		}
		if( astRType != astType ){
			if( CcTypeIsInteger( astRType ) ){
				varRight = ccCalCastInt2Floating( CcValueGetInteger( astRV ), astType );
			}else{
				varRight = CcValueGetFloating( astRV );
			}
		}else{
			varRight = CcValueGetFloating( astRV );
		}
		varLeft = ccCalAdditiveFloating( varLeft, varRight );
		return CcValueAddFloating( astType, varLeft );
	}
}
/*
 * CcCalSubtraction
 * 		calculate -
 * 		@astLV  operand
 * 		@astRV  operand
 * 		@astType  type of result
 */
AST CcCalSubtraction( AST astLV, AST astRV, AST astType ){
	AST astLType = stValueInfoAccess.type.get( astLV );
	AST astRType = stValueInfoAccess.type.get( astRV );

	if( CcTypeIsInteger( astType )){
		VARVALUE varLeft;
		VARVALUE varRight;
		if( astLType != astType ){
			if( CcTypeIsInteger( astLType ) ){
				varLeft = ccCalCastInt2Int(  CcValueGetInteger( astLV ), astType );
			}else{
				varLeft = ccCalCastFloating2Int( CcValueGetFloating( astLV ), astType );
			}
		}else{
			varLeft = CcValueGetInteger( astLV );
		}
		if( astRType != astType ){
			if( CcTypeIsInteger( astRType ) ){
				varRight = ccCalCastInt2Int( CcValueGetInteger( astRV ), astType );
			}else{
				varRight = ccCalCastFloating2Int( CcValueGetFloating( astRV ), astType );
			}
		}else{
			varRight = CcValueGetInteger( astRV );
		}
		varLeft = ccCalSubtractionInteger( varLeft, varRight );
		if( varLeft.overflow == CAL_OVERFLOW ){
			gblCalcuteFlg = CAL_OVERFLOW;
		}
		return CcValueAddVarValue( astType, varLeft );
	}else{
		DOUBLE varLeft;
		DOUBLE varRight;
		if( astLType != astType ){
			if( CcTypeIsInteger( astLType ) ){
				varLeft = ccCalCastInt2Floating(  CcValueGetInteger( astLV ), astType );
			}else{
				varLeft = CcValueGetFloating( astLV );
			}
		}else{
			varLeft = CcValueGetFloating( astLV );
		}
		if( astRType != astType ){
			if( CcTypeIsInteger( astRType ) ){
				varRight = ccCalCastInt2Floating( CcValueGetInteger( astRV ), astType );
			}else{
				varRight = CcValueGetFloating( astRV );
			}
		}else{
			varRight = CcValueGetFloating( astRV );
		}
		varLeft = ccCalSubtractionFloating( varLeft, varRight );
		return CcValueAddFloating( astType, varLeft );
	}
}
/*
 * CcCalCastTo
 * 		calculate cast
 * 		@astValue  operand
 * 		@astType  the destination type
 */
AST CcCalCastTo( AST astValue, AST astType ){
	AST  astOrgT = stValueInfoAccess.type.get( astValue );
	if( CcTypeIsInteger( astOrgT ) && CcTypeIsInteger( astType )){
		VARVALUE value = CcValueGetInteger( astValue );
		value = ccCalCastInt2Int( value, astType );
		return CcValueAddVarValue( CcTypeIntegerPromotion( astType ), value );
	}else if( CcTypeIsInteger( astOrgT ) ){
		VARVALUE value = CcValueGetInteger( astValue );
		return CcValueAddFloating( astType, ccCalCastInt2Floating( value, astType ));
	}else if( CcTypeIsInteger( astType )){
		DOUBLE val = CcValueGetFloating( astValue );
		return CcValueAddVarValue( CcTypeIntegerPromotion( astType ),
				ccCalCastFloating2Int( val, astType ));
	}
	return CcValueAddFloating( astType , CcValueGetFloating( astValue ));
}
/*
 * CcCalCatchFlagValue
 * 		catch the abnormal flags when calculating
 */
S4 CcCalCatchFlagValue( VOID ){
	S4 flag = gblCalcuteFlg;
	gblCalcuteFlg = 0;
	return flag;
}
